// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package options

import (
	"fmt"
	meshconfig "istio.io/api/mesh/v1alpha1"
	"istio.io/pkg/log"
	"os"
	"tmlake.com/api-gateway/pkg/config/constants"
	"tmlake.com/api-gateway/pkg/jwt"
	"tmlake.com/api-gateway/pkg/security"
	"tmlake.com/api-gateway/security/pkg/nodeagent/cafile"
)

func NewSecurityOptions(proxyConfig *meshconfig.ProxyConfig, tokenManagerPlugin string) (*security.Options, error) {
	o := &security.Options{
		CAEndpoint:                     caEndpointEnv,
		CAProviderName:                 caProviderEnv,
		OutputKeyCertToDir:             outputKeyCertToDir,
		ProvCert:                       provCert,
		ClusterID:                      clusterIDVar.Get(),
		FileMountedCerts:               fileMountedCertsEnv,
		WorkloadNamespace:              PodNamespaceVar.Get(),
		ServiceAccount:                 serviceAccountVar.Get(),
		XdsAuthProvider:                xdsAuthProvider.Get(),
		TrustDomain:                    trustDomainEnv,
		Pkcs8Keys:                      pkcs8KeysEnv,
		ECCSigAlg:                      eccSigAlgEnv,
		SecretTTL:                      secretTTLEnv,
		FileDebounceDuration:           fileDebounceDuration,
		SecretRotationGracePeriodRatio: secretRotationGracePeriodRatioEnv,
		CertSigner:                     certSigner.Get(),
		CARootPath:                     cafile.CACertFilePath,
		CertChainFilePath:              security.DefaultCertChainFilePath,
		KeyFilePath:                    security.DefaultKeyFilePath,
		RootCertFilePath:               security.DefaultRootCertFilePath,
	}

	o, err := SetupSecurityOptions(proxyConfig, o, jwtPolicy.Get(),
		credFetcherTypeEnv, credIdentityProvider)
	if err != nil {
		return o, err
	}

	return o, nil
}

func SetupSecurityOptions(proxyConfig *meshconfig.ProxyConfig, secOpt *security.Options, jwtPolicy,
	credFetcherTypeEnv, credIdentityProvider string) (*security.Options, error) {
	var jwtPath string
	switch jwtPolicy {
	case jwt.PolicyThirdParty:
		log.Info("JWT policy is third-party-jwt")
		jwtPath = constants.TrustworthyJWTPath
	case jwt.PolicyFirstParty:
		log.Info("JWT policy is first-party-jwt")
		jwtPath = constants.K8sSAJwtFileName
	default:
		log.Info("Using existing certs")
	}

	o := secOpt
	o.JWTPath = jwtPath

	// If not set explicitly, default to the discovery address.
	if o.CAEndpoint == "" {
		o.CAEndpoint = proxyConfig.DiscoveryAddress
		o.CAEndpointSAN = istiodSAN.Get()
	}

	if o.ProvCert != "" && o.FileMountedCerts {
		return nil, fmt.Errorf("invalid options: PROV_CERT and FILE_MOUNTED_CERTS are mutually exclusive")
	}
	return o, nil
}

// CheckGkeWorkloadCertificate returns true when the GKE workload certificate
// files are present under the path for GKE workload certificate. Otherwise, return false.
func CheckGkeWorkloadCertificate(certChainFilePath, keyFilePath, rootCertFilePath string) bool {
	if _, err := os.Stat(certChainFilePath); err != nil {
		return false
	}
	if _, err := os.Stat(keyFilePath); err != nil {
		return false
	}
	if _, err := os.Stat(rootCertFilePath); err != nil {
		return false
	}
	return true
}
